package com.xdap.init.service.impl;

import com.xdap.api.moudle.formconfig.pojo.FormComponent;
import com.xdap.api.moudle.formconfig.pojo.XdapFormConfig;
import com.xdap.api.moudle.privateapaas.datamodel.pojo.ModelWithFieldVo;
import com.xdap.common.dao.InitFormDao;
import com.xdap.common.utils.FormDataUtil;
import com.xdap.init.dao.ModelFeildDao;
import com.xdap.init.pojo.po.DataModelField;
import com.xdap.init.service.InitModelFeildService;
import com.xdap.init.service.JudgeModelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class JudgeModelServiceImpl implements JudgeModelService {
    @Autowired
    private InitModelFeildService initModelFeildService;
    @Autowired
    private ModelFeildDao modelFeildDao;
    @Autowired
    private InitFormDao initFormDao;
    private DataModelField field;

    @Override
    public String judgePo(String filePath) {
        String result = "";
        File file = new File(filePath);
        if (!file.exists()) {
            return "未找到对应的文件或者文件夹，不对文件夹进行遍历处理";
        }
        File[] list = file.listFiles();
        // 拿到整个文件列表，只处理带@TableName的文件
        // 先判断是不是文件夹，如果是文件夹，往下查询；如果不是文件夹，解析成String，然后对数据进行处理
        for (File childFile : list) {
            result += judgeFile(childFile);
        }

        return result;
    }

    /**
     * @auth lishushu
     * @2023/4/20 17:21
     * @desc {处理模型字段的实际注释都为页面表单上的中文注释}
     **/
    @Override
    public String judgeModel(String formId) {
        // 获取mongo的模型表单信息
        XdapFormConfig xdapFormConfig = initFormDao.getXdapFormConfig(formId);
        String formName = xdapFormConfig.getFormName(); // TODO 之后考虑一下如何把这个名字修改到模型表中
        String result = judgeModelByFormConfig(xdapFormConfig);
        return result;
    }

    // TODO  如果一个表单会在多个表单中使用，每个表单中的文字展示是不一样的，可能会导致model_field中的字段展示最后校验的那个表单的名称
    @Override
    public String judgeModelByFormConfig(XdapFormConfig xdapFormConfig) {
        String result = "";
        // 所有的字段信息
        List<FormComponent> parentFormComponents = xdapFormConfig.getDetailPage().getFormComponents();
        List<FormComponent> formComponents = FormDataUtil.getChildFc(parentFormComponents);
        formComponents.addAll(parentFormComponents);
        List<ModelWithFieldVo> modelWithFieldVoList = xdapFormConfig.getModelWithFieldVoList();

        for (ModelWithFieldVo model : modelWithFieldVoList) {
            Boolean mainModel = model.getMainModel();
            // 处理模型字段表和页面上字段的区别
            String modelCode = model.getModelCode();
            String modelName = model.getModelName();
            List<DataModelField> fields = modelFeildDao.getFields(modelCode);
            for (DataModelField field : fields) {
                try {
                    String fieldCode = field.getFieldCode();
                    // 获取所有字段实际的参数
                    List<FormComponent> fcList = formComponents.stream()
                            .filter(fc -> (modelCode + "." + fieldCode).equals(fc.getModelField()))
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(fcList)) {
                        FormComponent formComponent = fcList.get(0);
                        String label = formComponent.getLabel();
                        String fieldName = field.getFieldName();
                        if (!fieldName.equals(label)) {
                            field.setFieldName(label);
                            modelFeildDao.updateField(field);
                        }
                    }
                } catch (Exception e) {
                    log.error("在更新{}的时候报错:{}", field, e);
                }
            }
            result += "更新了模型：" + modelCode + "(" + modelName + ")的字段，保持和页面名称保持一致\n";
        }

        return result;
    }


    /**
     * @auth lishushu
     * @2023/4/17 14:36
     * @desc {}
     **/
    public String judgeFile(File file) {
        String result = "";
        String filePath = file.getAbsolutePath();
        if (file.isDirectory()) {
            log.info("{}是文件夹，需要遍历查询", filePath);
            if (filePath.contains("service") || filePath.contains("controller") || filePath.contains("dao")
                    || filePath.contains("config") || filePath.contains("unit")) {
                log.info("service/controller/dao/config/unit等文件不需要做过滤");
                return "";
            }
            File[] list = file.listFiles();
            for (File childFile : list) {
                result += judgeFile(childFile);
            }
        } else {
            log.info("{}是文件，需要解析处理,如果不是.java结尾，就不会处理", filePath);
            if (filePath.endsWith(".java")) {
                log.info("开始处理{}文件", filePath);
                result += getData(filePath);
            }
        }
        return result;
    }


    public String getData(String javaFilePath) {
        String result = "";
        try {
            String encoding = getCode(javaFilePath);

            //考虑到编码格式
            InputStreamReader read = new InputStreamReader(new FileInputStream(javaFilePath), encoding);
            BufferedReader bufferedReader = new BufferedReader(read);
            StringBuffer data = new StringBuffer();
            String lineTxt = null;
            while ((lineTxt = bufferedReader.readLine()) != null) {
                data.append(lineTxt);
            }
            read.close();

            // TODO 对数据进行处理，找到对应的tableName，然后生成新的对象
            log.info("{}--解析出来的文本为:\n\n{}", javaFilePath, data);
            result += judgeData(javaFilePath, data);
        } catch (Exception e) {
            log.error("{}：解析报错:{}", javaFilePath, e);
            result = javaFilePath + "解析文件失败;";
        }

        return result;

    }

    public String judgeData(String javaFilePath, StringBuffer data) {
        String result = "";
        String orginData = data.toString();
        if (!orginData.contains("@Table(")) {
            log.info("{}不是po对象，不需要重新校验", javaFilePath);
            result += javaFilePath + "--不需要重新校验;";
            return result;
        }
        File file = new File(javaFilePath);


        // 处理
        int first = orginData.indexOf("@Table(\"") + 8;
        int end = orginData.indexOf("\")");
        // 判断问题的情况
        while (end < first) {
            end = orginData.indexOf("\")", end + 2);
        }
        String tableName = orginData.substring(first, end);
        if (tableName.startsWith("xdap") || tableName.startsWith("apaas")) {
            return tableName + "不处理apaas自带的表；";
        }

        String newData =
                "\t@Column(\"id\") \n\tprivate String id; \n" +
                        "\t@Column(\"document_id\") \n\tprivate String documentId; \n" +
                        "\t@Column(\"tab_doc_id\") \n\tprivate String tabDocId; \n" +
                        "\t@Column(\"status\") \n\tprivate String status; \n \n\n";
        List<DataModelField> fields = modelFeildDao.getFields(tableName);

        newData = initModelFeildService.getData(fields, newData, true);


        String name = file.getName();
        String path = file.getParent();


        // 把原始的文件删除
        file.deleteOnExit();
        int publicClass = orginData.indexOf("public class");
        // 获取到第一个大括号的位置
        int i = orginData.indexOf("{", publicClass + 11);
        String titleClass = orginData.substring(0, i);
        // 美化代码
        titleClass = titleClass.replaceAll(";", ";\n"); // 所有引用后面加一个换行
        titleClass = titleClass.replaceAll("@", "\n@"); // @注解前加一个换行
        titleClass = titleClass.replaceFirst(";", ";\n"); // package的；后面再加一个换行
        titleClass = titleClass.replaceFirst("public", "\npublic"); // package的；后面再加一个换行

        // 操作注释的美化
        titleClass = titleClass.replaceFirst("\\/\\*\\*", "____start__#############____");
        if (titleClass.contains("**\\/")) { // 多行注释/** 注释内容 **/的后面，如果是*/ 或者 **/的判断
            titleClass = titleClass.replaceFirst("\\*\\*\\/", "____end___=============____");
        } else {
            titleClass = titleClass.replaceFirst("\\*\\/", "____end___=============____");
        }
        // 因为上面加了@的换行，导致*@之间的换行有点问题，再处理一遍
        if (titleClass.contains("*\n@")) {
            titleClass = titleClass.replaceAll("\\*\n@", "\n*@");

        } else {
            titleClass = titleClass.replaceAll("\\*", "\n*");
        }
        titleClass = titleClass.replaceFirst("____start__#############____", "\n\\/\\*\\*");
        titleClass = titleClass.replaceFirst("____end___=============____", "\n\\*\\*\\/\n");

        if (!titleClass.endsWith("{")) {
            titleClass += "{\n";
        }

        // 数据的引用正常
        newData = titleClass + newData + "\n\n}";

        initModelFeildService.createJava(path, name, newData);
        result += javaFilePath + "--解析成功";
        return result;

    }


    public String getCode(String filePath) throws Exception {
        // 这个方法是针对txt的，所以对java没啥用，暂时默认就是UTF-8,剩下的以后再说
        BufferedInputStream bin = new BufferedInputStream(new FileInputStream(filePath));
        int p = (bin.read() << 8) + bin.read();
        String code = null;
        switch (p) {
            case 0xefbb:
                code = "GBK";
                break;
            case 0xfffe:
                code = "Unicode";
                break;
            case 0xfeff:
                code = "UTF-16BE";
                break;
            default:
                code = "UTF-8";

        }
        log.info("本文件实际的格式为：{}", code);
        return code;
    }
}
